package com.jt.service;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import com.jt.vo.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.UUID;

@Service
//@Transactional  //当前类中的所有的方法都有事务控制 增/删/改需要事务  查询不要事务.
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.selectList(null);
    }


    /**
     * 需求:
     *      1.根据用户名和密码查询数据库
     *      2.将密码进行加密处理 md5加密方式
     *      3.如果用户名和密码正确 返回token
     *      4 UUID: 每次生成的UUID几乎不重复.   重复概率 2^128/1
     *        b809cd3e-f4fa-11eb-b396-52152e05da50
     * @param user  作用: 在未来生成API文档时 有效果 一般都是默认的
     * @return
     */
    @Override
    public String login(User user) {

        // 1.将密码进行加密处理
        String password = user.getPassword();// 获取明文

        // 2.将字符串转换为字节数组
        byte[] passByte = password.getBytes();
        //明文加密
        String md5Pass = DigestUtils.md5DigestAsHex(passByte);

        // 3.根据用户名和密文查询数据库
        // Sql:select * from user where uname="xxx" and pa = "xxx"

//        QueryWrapper<User> queryWrapper = new QueryWrapper();
//        queryWrapper.eq("username",user.getUsername())
//                    .eq("password",user.getPassword());
        //根据对象中不为null的属性充当where条件！！！
        user.setPassword(md5Pass);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
        //用户名和密码是否与数据库中的匹配!!!!!
        //BUG: 根据MD5加密 admin123456 可能由于windows版本问题 可能出现偏差
        //  admin123456 A  !=  B  将数据库中的密码改为B
        // 4.从数据库中获取结果
        User userDB= userMapper.selectOne(queryWrapper);

        // 5.检验结果是否有效！！！
        //用户密码错误 返回null
        if (userDB == null) {
            return null;
        }
        //如果程序执行到该行，则用户输入正确，返回一个token
        String token = UUID.randomUUID().toString()
                .replace("-","");
        return token;
    }

    /**
     * 需求：进行分页查询  总数  分页后的结果
     * 要求每页20条
     * Sql：select *  user limit 起始位置，每页条数
     * 第n页：rows为每页条数
     *      select * from user limit (n-1)*rows,rows
     * @param pageResult
     * @return
     *
     *  方法实现：
     *          1.手写SQL语句 在mappers中配置xml
     *          若SQL语句简单，可以直接在mapper层写接口注解完成开发(写在对应的方法)
     *          select("sql")、delete("sql")、update("sql")、select("sql")
     *          2.使用mp  mapper层接口要实现BaseMapper<User>接口
     *          注意BaseMapper接口必须添加泛型对象  否则映射表报错。
     */

    /*  //方式一：
    @Override
    public PageResult getUserList(PageResult pageResult) {
        //根据参数动态的执行分页查询
        //起始位置
        Integer start = (pageResult.getPageNum() - 1)*pageResult.getPageSize();
        //每页调试
        Integer size = pageResult.getPageSize();
        //分页结果
        List<User> userList = userMapper.findUserListByPage(start,size);
        //获取全部记录 利用java自动拆装箱的规范
        long total = userMapper.selectCount(null);
        //封装数据实现返回
        pageResult.setTotal(total).setRows(userList);
        return pageResult;
    }*/

    //方式二：
    /**
     * 以MP的方式分页查询
     * 需求：
     *  1.分页查询 List<User>
     *  2.
     * @param pageResult
     * @return
     */
    @Override
    public PageResult getUserList(PageResult pageResult) {

        //第一部分 实现数据的封装!!!
        // 参数一：page分页对象 加泛型方便链式
        Page<User> page = new Page(pageResult.getPageNum(), pageResult.getPageSize());
        // 参数二：分页查询条件  username模糊查询
        /*难点：若用户没有传递query ， like依然会拼接参数
          即：where username like %%
          解决办法：用动态拼接 传参拼接，不传参则不拼接
          使用带condition的like
          condition：true 拼接like关键字
          condition：false 不拼接like关键字
         */
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //判断用户是否传参  如果传参 返回true   反之 返回false
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        queryWrapper.like(flag,"userName",pageResult.getQuery());
        //规则：page两个参数   根据分页查询返回total/分页后的记录 4个参数
        page = userMapper.selectPage(page,queryWrapper);
        //根据分页对象获取记录
        List<User> userList = page.getRecords();
        //根据分页对象获取总数
        long total = page.getTotal();
        //封装VO对象  返回数据
        pageResult.setTotal(total).setRows(userList);
        return pageResult;
    }

    @Override
    public void updateStatus(User user) {

        //根据其中不为null的元素当作set条件   id当作唯一的where条件
        userMapper.updateById(user);
    }

    /**
     * 新增入库：
     *      1.密码需要加密处理
     *      2.应该赋予默认状态 true
     *      3.需要添加时间  创建/修改
     * @param user
     */
    @Override
    @Transactional
    public void addUser(User user) {

        //1.密码加密
        byte[] bytes = user.getPassword().getBytes();
        String md5Pass = DigestUtils.md5DigestAsHex(bytes);
        //2.赋予状态
        user.setStatus(true);
        //3.添加时间  保证时间统一
//        放到MyMetaObjectHandler类处理
//        Date date = new Date();
//        user.setCreated(date).setUpdated(date);

        //4.数据入库
        userMapper.insert(user);
    }


    /**
     * 事务控制  控制数据库，注解加在业务层就好,用于增删改就行
     * 关于Spring中的事务策略说明
     *  0.Spring内部有事务的管理器,默认开启.
     *  1.Spring只负责拦截运行时异常.
     *    异常类型:  1.运行时异常  2.检查异常/编译异常 由程序员自己控制
     *  2.属性1: rollbackFor 可以配置特殊的异常类型.则可以控制事务.
     *    属性2: noRollbackFor 可以配置异常类型 遇到某种异常不回滚.
     *    @Transactional( rollbackFor=异常类名)
     *    @Transactional(rollbackFor = ArithmeticException.class)
     * @param id
     */
    @Override
    @Transactional  //Spring默认提供的事务控制的注解
    public void deleteUserById(Integer id) {
        userMapper.deleteById(id);
    }

    @Override
    public User getUserById(Integer id) {

        return userMapper.selectById(id);
    }

    //参数: id主键  电话/邮箱
    //语法: 根据对象中不为null的属性当作set条件 id当作唯一where条件
    @Override
    //@Transactional(rollbackFor = ArithmeticException.class)
    @Transactional
    public void updateUser(User user) {
        //int a = 1/0;
        userMapper.updateById(user);
    }


}